﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using System.Text;

namespace chesslibrary.cs
{
    public delegate void ChessSimpleEvent();
    public delegate void ChessMoveEvent(move_pieces m);
    public class game_chess:board_chess
    {
    	private player white;
		private player black;
		private rules_chess rules;
		private color_pieces active;
		public event ChessSimpleEvent StartGame;
		public event ChessSimpleEvent EndGame;
		public event ChessSimpleEvent MoveUndone;
		public event ChessMoveEvent MoveExecuted;
        public game_chess(player white, player black)
		{
			this.white=white;
			this.black=black;

			active=white.Side;
            rules=new rules_chess(this);
		}
        public color_pieces ActiveSide()
		{
			return active;
		}
		public ArrayList GetValidMoves(cell_chess cell)
		{
			return GetValidMoves(this[cell]);
		}
		internal ArrayList GetValidMoves(properties_cell s)
		{
			if (s.IsEmpty())
			{
				return new ArrayList();
			}
            if (s.pieces_chess.IsEnemyOf(active))
			{
				return new ArrayList();
			}
			return rules.getMoves(s);
		}
        public void addChessListener(ChessListener listener)
		{
			StartGame+=new ChessSimpleEvent(listener.Begin);
			EndGame+=new ChessSimpleEvent(listener.End);
			MoveUndone+=new ChessSimpleEvent(listener.UndoMove);
			MoveExecuted+=new ChessMoveEvent(listener.Move);
		}
        public void removeChessListener(ChessListener listener)
		{
			StartGame-=new ChessSimpleEvent(listener.Begin);
			EndGame-=new ChessSimpleEvent(listener.End);
			MoveUndone-=new ChessSimpleEvent(listener.UndoMove);
			MoveExecuted-=new ChessMoveEvent(listener.Move);
		}
        public void Start()
		{
			setupBoard();
			active=color_pieces.White;

			raiseBeginEvent();
		}
        public void End()
		{
			raiseEndEvent();
		}
        private void raiseBeginEvent()
		{
		if (StartGame!=null)
				StartGame();
		}
        private void raiseEndEvent()
		{
			if (EndGame!=null)
				EndGame();
		}
        private void raiseMoveEvent(move_pieces move)
		{
			if (MoveExecuted!=null)
				MoveExecuted(move);
		}
        private void raiseUndoEvent()
		{
			if (MoveUndone!=null)
				MoveUndone();
		}
        public void undo()
		{
			if (base.UndoMove())
			{
				switchPlayer();
				raiseUndoEvent();
			}
		}
        private void switchPlayer()
		{
			active=active.Enemy;
		}
        //public void movePiece(string s)
        //{
        //    //cell_chess Begin=new cell_chess(s.Substring(0,2));
        //    //cell_chess end=new cell_chess(s.Substring(2,2));
        //    movePiece(Begin.Row,Begin.Col,end.Row,end.Col);
        //}
        public void movePiece(cell_chess Begin,cell_chess end)
		{
			movePiece(Begin.Row,Begin.Col,end.Row,end.Col);
		}
		public void movePiece(int rowBegin,int colBegin,int rowEnd,int colEnd)
		{
			properties_cell s=this[new cell_chess(rowBegin,colBegin)];
			properties_cell t=this[new cell_chess(rowEnd,colEnd)];
            if (!s.IsOwnedBy(active))
			{
				throw(new ChessException("Illegal move",rowBegin,rowEnd));
			}
            if (s.IsEmpty())
			{
				throw new ChessException("move attempted at an empty field");
			}
            move_pieces m=rules.createMove(s,t);
            if (m is grade)
			{
				setgradePiece((grade)m);
			}
			ExecuteMove(m);
			switchPlayer();
			if (rules.isCheck(ActiveSide()))
			{
				m.Check();
				if (rules.isCheckmate(ActiveSide()))
				{
					m.Checkmate();
				}
			}
			if (rules.isStalemate(ActiveSide()))
			{
				m.Stalemate();
			}
			raiseMoveEvent(m);
		}
    	private void setgradePiece(grade m)
		{
			player p;
			if (m.Owner==color_pieces.White)
				p=white;
			else
				p=black;
			pieces_chess.Kind type=p.promote();
			pieces_chess promotepiece;
			switch (type)
			{
				case pieces_chess.Kind.pieces_rook:
                    promotepiece = new pieces_rook(m.Owner);
					break;
                case pieces_chess.Kind.pieces_bishop:
                    promotepiece = new pieces_bishop(m.Owner);
					break;
                case pieces_chess.Kind.pieces_knight:
                    promotepiece = new pieces_knight(m.Owner);
					break;
				default:
                    promotepiece = new pieces_queen(m.Owner);
					break;
			}
			m.SetGradePiece(promotepiece);
		}
    }
}
